/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkGbMediaUt.h"
#include "MkEvent/MkEvent.h"
#include "MkEvent/MkEventPool.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkUtil.h"
#include "MkMedia/MkFileSource.h"
#include "MkMedia/MkMediaConsumer.h"
#include "MkUtil/MkLog.h"
#include "MkRtp/MkRtpServerPool.h"
#include "MkGbMedia/MkGbMediaServer.h"
#include "MkGbMedia/MkGbMediaEndUser.h"
#include <gtest/gtest.h>
#ifndef _WIN32
#include "MkUtil/MkMemQueue.h"
#endif

CMkGbMediaServerUt::CMkGbMediaServerUt()
{

}

CMkGbMediaServerUt::~CMkGbMediaServerUt()
{

}

void CMkGbMediaServerUt::SetUp()
{
    CMkSipUtil::GetInstance().SetMessageContentDebug(TRUE);
    m_ServerId = "340200000020000001";
    m_EndUserId = "340200000040000001";
    m_GbRealm = "3402000000";
    m_pGbMediaServer = nullptr;
    m_pEventPool = nullptr;
    m_pTimer = nullptr;
    m_pH264FileSource = nullptr;
    m_pH265FileSource = nullptr;
    m_pAacFileSource = nullptr;
    m_pGbEndUser = nullptr;
    m_pMediaConsume = nullptr;
    m_pPublishedSource = nullptr;

    m_pEventPool = new CMkEventPool;
    m_pEventPool->Start(1);
    m_pTimer = new CMkTimer;
    m_pTimer->StartTimerThread();

    m_pRtpServerPool = new CMkRtpServerPool(m_pEventPool, m_pTimer);
    m_pRtpServerPool->Start();
    m_pRtpPoolClientUse = new CMkRtpServerPool(m_pEventPool, m_pTimer);
    m_pRtpPoolClientUse->SetBeginPort(40500);
    m_pRtpPoolClientUse->Start();

    MkString H264FileName = MkString(MkUtSourcePath) + "/test.264";
    MkString H265FileName = MkString(MkUtSourcePath) + "/test.265";
    MkString AacFileName = MkString(MkUtSourcePath) + "/test.aac";
    FILE *fp264 = fopen(H264FileName.c_str(), "rb");
    FILE *fp265 = fopen(H265FileName.c_str(), "rb");
    FILE *fpAac = fopen(AacFileName.c_str(), "rb");

    m_pH264FileSource = new CMkH264FileSource(fp264, nullptr);
    m_pH265FileSource = new CMkH265FileSource(fp265, nullptr);
    m_pAacFileSource = new CMkAacFileSource(fpAac, nullptr);
    m_WaitHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);

    Uint32 ErrorCode = m_pH264FileSource->StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(NoneError, ErrorCode);
    ErrorCode = m_pH265FileSource->StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(NoneError, ErrorCode);
    ErrorCode = m_pAacFileSource->StartMediaSource(nullptr, nullptr);
    EXPECT_EQ(NoneError, ErrorCode);

    ErrorCode = m_pH264FileSource->GetNextFrame(m_VecPacket264);
    EXPECT_EQ(NoneError, ErrorCode);
    EXPECT_EQ(FALSE, m_VecPacket264.empty());

    ErrorCode = m_pH265FileSource->GetNextFrame(m_VecPacket265);
    EXPECT_EQ(NoneError, ErrorCode);
    EXPECT_EQ(FALSE, m_VecPacket265.empty());

    ErrorCode = m_pAacFileSource->GetNextFrame(m_VecPacketAac);
    EXPECT_EQ(NoneError, ErrorCode);
    EXPECT_EQ(FALSE, m_VecPacketAac.empty());

    FILE *fpPublish264 = fopen(H264FileName.c_str(), "rb");
    m_pH264PublishSource = new CMkH264FileSource(fpPublish264, m_pTimer);

    MkMediaCallbacks MediaCbs;
    MediaCbs.GetSourceParamCb = [this](const MkString& Path, CMkVideoParam& VideoParam, CMkAudioParam& AudioParam, Uint32& Duration, Uint32& FileSize, MkString& SourceSession) {
        MkDebugLog("path:%s get media param\n", Path.c_str());
        if ("/live/34020000001310000001" == Path) {
            VideoParam = m_pH264FileSource->GetVideoParam();
            AudioParam = m_pAacFileSource->GetAudioParam();
            Duration = 1;
            FileSize = 100;
        } else if ("/live/34020000001310000002" == Path) {
            VideoParam = m_pH265FileSource->GetVideoParam();
            AudioParam = m_pAacFileSource->GetAudioParam();
            Duration = 1;
            FileSize = 100;
        } else if ("/live/34020000001310000003" == Path) {
            VideoParam = m_pH264FileSource->GetVideoParam();
            AudioParam = CMkAudioParam();
            Duration = 1;
            FileSize = 100;
        } else if ("/live/34020000001310000004" == Path) {
            VideoParam = m_pH265FileSource->GetVideoParam();
            AudioParam = CMkAudioParam();
            Duration = 1;
            FileSize = 100;
        }/* else if ("/live/testAac_play" == Path) {
            VideoParam = CMkVideoParam();
            AudioParam = m_pAacFileSource->GetAudioParam();
            Duration = 1;
            FileSize = 100;
        } */else {
            return SystemError;
        }
        SourceSession = Path;
        return NoneError;
    };

    MediaCbs.ConsumerAddCb = [this](const MkString& SourceSession, CMkMediaConsume* pConsume, CMkMediaConsumer* pConsumer) {
        MkDebugLog("source session:%s send packet\n", SourceSession.c_str());
        m_pMediaConsume = pConsume;
        pConsume->AddConsumer(pConsumer);
        Uint8 pBuf[Len1K] = { 0 };
        CMkMediaSource MediaSource(MkMediaSourceFileFlv);
        if ("/live/34020000001310000001" == SourceSession) {
            MediaSource.SetVideoParam(m_pH264FileSource->GetVideoParam());
            MediaSource.SetAudioParam(m_pAacFileSource->GetAudioParam());
            MediaSource.AddCacheEsPacket(*m_VecPacket264.begin());
            MediaSource.AddCacheEsPacket(*m_VecPacketAac.begin());
            pConsume->ConsumeEsPacket(&MediaSource, *m_VecPacket264.begin(), pBuf, Len1K);
            pConsume->ConsumeEsPacket(&MediaSource, *m_VecPacketAac.begin(), pBuf, Len1K);
        } else if ("/live/34020000001310000002" == SourceSession) {
            MediaSource.SetVideoParam(m_pH265FileSource->GetVideoParam());
            MediaSource.SetAudioParam(m_pAacFileSource->GetAudioParam());
            MediaSource.AddCacheEsPacket(*m_VecPacket265.begin());
            MediaSource.AddCacheEsPacket(*m_VecPacketAac.begin());
            pConsume->ConsumeEsPacket(&MediaSource, *m_VecPacket265.begin(), pBuf, Len1K);
            pConsume->ConsumeEsPacket(&MediaSource, *m_VecPacketAac.begin(), pBuf, Len1K);
        } else if ("/live/34020000001310000003" == SourceSession) {
            pConsume->ConsumeEsPacket(m_pH264FileSource, *m_VecPacket264.begin(), pBuf, Len1K);
        } else if ("/live/34020000001310000004" == SourceSession) {
            pConsume->ConsumeEsPacket(m_pH265FileSource, *m_VecPacket265.begin(), pBuf, Len1K);
        } /*else if ("/live/34020000001310000005" == SourceSession) {
            pConsume->ConsumeEsPacket(m_pAacFileSource, *m_VecPacketAac.begin(), pBuf, Len1K);
        }*/
        return NoneError;
    };
    MediaCbs.SourceAddCb = [this](CMkMediaSource* pSource) {
        m_pPublishedSource = pSource;
        return NoneError;
    };
    MediaCbs.ConsumerClosedCb = [this](const MkString& SourceSession, const MkMediaConsumeType& ConsumeType, const MkString& ConsumerSession) {
        if (m_pMediaConsume) {
            m_pMediaConsume->DeleteConsumer(ConsumerSession);

        }
        return NoneError;
    };
    MediaCbs.SourceDeleteCb = [](const MkString& SourceSession) {
        return NoneError;
    };

    m_pGbMediaServer = new CMkGbMediaServer(m_pEventPool, m_pTimer, m_pRtpServerPool, nullptr, MediaCbs);
    while (1) {
        m_ServerPort = CMkUtil::GetRandomNumber() % 0xFFFF;
        MkGbStartParam Param;
        Param.SipId = m_ServerId;
        Param.SipRealm = m_GbRealm;
        Param.LocalHost = "127.0.0.1";
        Param.LocalPort = m_ServerPort;
        Param.MappingHost = "";
        Param.MappingPort = 0;
        Param.RegisterExpires = 1;
        Param.SubscribeExpires = 1;
        Param.bCheckDstId = FALSE;
        if (NoneError == m_pGbMediaServer->Start(Param, "live")) {
            break;
        }
    }

    m_pGbEndUser = new CMkGbMediaEndUser(m_pEventPool, m_pTimer);
    while (1) {
        m_EndUserPort = CMkUtil::GetRandomNumber() % 0xFFFF;
        MkGbStartParam Param;
        Param.SipId = m_EndUserId;
        Param.SipRealm = m_GbRealm;
        Param.LocalHost = "127.0.0.1";
        Param.LocalPort = m_EndUserPort;
        Param.MappingHost = "";
        Param.MappingPort = 0;
        Param.RegisterExpires = 1;
        Param.SubscribeExpires = 1;
        Param.bCheckDstId = FALSE;
        if (NoneError == m_pGbEndUser->Start(Param, 34000)) {
            break;
        }
    }
}

void CMkGbMediaServerUt::TearDown()
{
    CMkThread::ThreadSleep(100);
    m_pTimer->StopTimerThread();
    m_pEventPool->Stop();
    m_pRtpServerPool->Stop();
    m_pRtpPoolClientUse->Stop();
    MkDelete(m_pMediaConsume);
    MkDelete(m_pGbMediaServer);
    MkDelete(m_pH264FileSource);
    MkDelete(m_pH265FileSource);
    MkDelete(m_pAacFileSource);
    MkDelete(m_pH264PublishSource);
    MkDelete(m_pPublishedSource);
    MkDelete(m_pGbEndUser);
    CloseHandle(m_WaitHandle); 
    MkDelete(m_pRtpServerPool);
    MkDelete(m_pRtpPoolClientUse);
    MkDelete(m_pTimer);
    MkDelete(m_pEventPool);
}

//TEST_F(CMkGbMediaServerUt, TcpSipTcpRtpPlay264AacTest)
//{
//    MkString SipUri = "sip:34020000001310000001@127.0.0.1:" + std::to_string(m_ServerPort);
//
//    m_pGbEndUser->Play(SipUri, TRUE, TRUE, 1, [this](Uint32 ErrorCode, const MkString& SessionId) {
//        EXPECT_EQ(NoneError, ErrorCode);
//        m_EndUserSession = SessionId;
//    }, [this](const MkString& SessionId) {
//        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
//    }, [this](const MkEsPacket& EsPacket, const CMkVideoParam& VideoParam, const CMkAudioParam& AudioParam) {
//        EXPECT_EQ(MkCodecAac, AudioParam.GetCodec());
//        EXPECT_EQ(MkCodecH264, VideoParam.GetCodec());
//        SetEvent(m_WaitHandle);
//        return NoneError;
//    });
//    WaitForSingleObject(m_WaitHandle, 0xFFFF);
//}

TEST_F(CMkGbMediaServerUt, UdpSipTcpRtpPlay265AacTest)
{
    MkString SipUri = "sip:34020000001310000002@127.0.0.1:" + std::to_string(m_ServerPort);

    m_pGbEndUser->Play(SipUri, FALSE, FALSE, 1, [this](Uint32 ErrorCode, const MkString& SessionId) {
        EXPECT_EQ(NoneError, ErrorCode);
        m_EndUserSession = SessionId;
    }, [this](const MkString& SessionId) {
        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
    }, [this](const MkEsPacket& EsPacket, const CMkVideoParam& VideoParam, const CMkAudioParam& AudioParam) {
        EXPECT_EQ(MkCodecAac, AudioParam.GetCodec());
        EXPECT_EQ(MkCodecH265, VideoParam.GetCodec());
        SetEvent(m_WaitHandle);
        return NoneError;
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkGbMediaServerUt, UdpSipPublishUdpRtpTest)
{
    MkString SipUri = "sip:34020000001320000001@127.0.0.1:" + std::to_string(m_ServerPort);
    m_pGbEndUser->Publish(SipUri, FALSE, FALSE, m_pH264PublishSource, [this](Uint32 ErrorCode, const MkString& SessionId) {
        EXPECT_EQ(NoneError, ErrorCode);
        m_EndUserSession = SessionId;
        m_pH264PublishSource->StartMediaSource(nullptr, nullptr);
    }, [this](const MkString& SessionId) {
        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkGbMediaServerUt, UdpSipPublishTcpRtpTest)
{
    MkString SipUri = "sip:34020000001320000001@127.0.0.1:" + std::to_string(m_ServerPort);
    m_pGbEndUser->Publish(SipUri, FALSE, TRUE, m_pH264PublishSource, [this](Uint32 ErrorCode, const MkString& SessionId) {
        EXPECT_EQ(NoneError, ErrorCode);
        m_EndUserSession = SessionId;
        m_pH264PublishSource->StartMediaSource(nullptr, nullptr);
    }, [this](const MkString& SessionId) {
        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkGbMediaServerUt, TcpSipPublishUdpRtpTest)
{
    MkString SipUri = "sip:34020000001320000002@127.0.0.1:" + std::to_string(m_ServerPort);
    m_pGbEndUser->Publish(SipUri, TRUE, FALSE, m_pH264PublishSource, [this](Uint32 ErrorCode, const MkString& SessionId) {
        EXPECT_EQ(NoneError, ErrorCode);
        m_EndUserSession = SessionId;
        m_pH264PublishSource->StartMediaSource(nullptr, nullptr);
    }, [this](const MkString& SessionId) {
        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkGbMediaServerUt, TcpSipPublishTcpRtpTest)
{
    MkString SipUri = "sip:34020000001320000002@127.0.0.1:" + std::to_string(m_ServerPort);
    m_pGbEndUser->Publish(SipUri, TRUE, TRUE, m_pH264PublishSource, [this](Uint32 ErrorCode, const MkString& SessionId) {
        EXPECT_EQ(NoneError, ErrorCode);
        m_EndUserSession = SessionId;
        m_pH264PublishSource->StartMediaSource(nullptr, nullptr);
    }, [this](const MkString& SessionId) {
        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkGbMediaServerUt, UdpSipPublishUdpRtp2Test)
{
    MkString SipUri = "sip:34020000001320000001@127.0.0.1:" + std::to_string(m_ServerPort);
    m_pGbEndUser->Publish2(SipUri, FALSE, FALSE, m_pH264PublishSource, [this](Uint32 ErrorCode, const MkString& SessionId) {
        EXPECT_EQ(NoneError, ErrorCode);
        m_EndUserSession = SessionId;
        m_pH264PublishSource->StartMediaSource(nullptr, nullptr);
    }, [this](const MkString& SessionId) {
        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkGbMediaServerUt, UdpSipPublishTcpRtp2Test)
{
    MkString SipUri = "sip:34020000001320000001@127.0.0.1:" + std::to_string(m_ServerPort);
    m_pGbEndUser->Publish2(SipUri, FALSE, TRUE, m_pH264PublishSource, [this](Uint32 ErrorCode, const MkString& SessionId) {
        EXPECT_EQ(NoneError, ErrorCode);
        m_EndUserSession = SessionId;
        m_pH264PublishSource->StartMediaSource(nullptr, nullptr);
    }, [this](const MkString& SessionId) {
        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkGbMediaServerUt, TcpSipPublishUdpRtp2Test)
{
    MkString SipUri = "sip:34020000001320000002@127.0.0.1:" + std::to_string(m_ServerPort);
    m_pGbEndUser->Publish2(SipUri, TRUE, FALSE, m_pH264PublishSource, [this](Uint32 ErrorCode, const MkString& SessionId) {
        EXPECT_EQ(NoneError, ErrorCode);
        m_EndUserSession = SessionId;
        m_pH264PublishSource->StartMediaSource(nullptr, nullptr);
    }, [this](const MkString& SessionId) {
        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}

TEST_F(CMkGbMediaServerUt, TcpSipPublishTcpRtp2Test)
{
    MkString SipUri = "sip:34020000001320000002@127.0.0.1:" + std::to_string(m_ServerPort);
    m_pGbEndUser->Publish2(SipUri, TRUE, TRUE, m_pH264PublishSource, [this](Uint32 ErrorCode, const MkString& SessionId) {
        EXPECT_EQ(NoneError, ErrorCode);
        m_EndUserSession = SessionId;
        m_pH264PublishSource->StartMediaSource(nullptr, nullptr);
    }, [this](const MkString& SessionId) {
        EXPECT_STREQ(m_EndUserSession.c_str(), SessionId.c_str());
        SetEvent(m_WaitHandle);
    });
    WaitForSingleObject(m_WaitHandle, 0xFFFF);
}